#include <iostream>
#include <fstream>
#include <vector>
#include <jsoncpp/json/json.h>
#include "Function.h"
#include "pbSpline.h"

using namespace std;
//原函数的构造，这里用到了函数e类/
class fun1 : public Function {
public:
    double operator()(const double &x) const {
        return 1.0 / (1 + 25 * x * x);
    }
    double get_diff(const double &x) const {
        return -50 * x / pow(1 + 25 * x * x, 2);
    }
    double get_secdiff(const double &x) const {
        return 50 * (75 * x * x - 1) / pow(1 + 25 * x * x, 3);
    }
}f;

int main() {
    //使用json格式输入数据，这里其实只用输入其区间的个数即可
    ifstream ifs("A_input.json");
    ofstream ofs1;
    ofs1.open("output/A_output.txt");


    Json::Reader reader;
    Json::Value obj;
    reader.parse(ifs, obj);


    double LeftBound = obj["A_LeftBound"].asDouble();
    double RightBound = obj["A_RightBound"].asDouble();
    std::vector<int> KnotsNum;
    for (auto i : obj["A_KnotsNum"]) {
        KnotsNum.push_back(i.asInt());
    }
    //读取数据完成接下来
    for (int i = 0; i < KnotsNum.size(); i++) {
        int N = KnotsNum[i];
        //插值条件
        vector<double> x, y;
        for (int j = 0; j < N; j++) {
            x.push_back(LeftBound + (RightBound - LeftBound) / (N - 1) * j);
            y.push_back(f(x[j]));
        }
        double cond_left = f.get_diff(x[0]);
        double cond_right = f.get_diff(x[N - 1]);

        //两种三次插值
        ppformSpline<3, Complete> spline_pp(x, y, cond_left, cond_right);
        Bspline<3, Complete> spline_b(x, y, cond_left, cond_right);

        //绘图点
        double PointsNum = 1001;
        vector<double> points;
        ofs1 << "When N = " << N << " : " << endl;
        ofs1 << "points: " << endl;
        for (int j = 0; j < PointsNum; j++) {
            points.push_back(LeftBound + j * (RightBound - LeftBound) / (PointsNum - 1));
	        ofs1 << points[j] << " ";
        }
        ofs1 << endl;
        ofs1 << "先计算原函数中各个间隔的中点的值" << endl;
        for (int j = 0; j < PointsNum; j++) {
	        ofs1 << f(points[j]) << " ";
        }

        ofs1 << endl;
        ofs1 << "再计算插值后P样条的相对应的值 " << endl;
        for (int j = 0; j < PointsNum; j++) {
            ofs1 << spline_pp(points[j]) << " ";
        }
        ofs1 << endl;

        ofs1 << endl;  
        ofs1 << endl;
        
        //计算误差
        double max_error_pp = 0;
        double max_error_b = 0;
        for (int j = 0; j < N - 1; j++) {
            if (fabs(spline_pp((x[j] + x[j + 1]) / 2) - f((x[j] + x[j + 1]) / 2)) > max_error_pp) {
                max_error_pp = spline_pp((x[j] + x[j + 1]) / 2) - f((x[j] + x[j + 1]) / 2);
            }
            if (fabs(spline_b((x[j] + x[j + 1]) / 2) - f((x[j] + x[j + 1]) / 2)) > max_error_b) {
                max_error_b = spline_pp((x[j] + x[j + 1]) / 2) - f((x[j] + x[j + 1]) / 2);
            }
        }
        ofs1 << "当 N = " << N << " : " << endl;
        ofs1 << "最大误差: " << max_error_pp << endl;
        ofs1 << endl;

    }

    ofs1.close();

    return 0;
}
